﻿//========================================================= 
/**@file H002PinExCmdDriver.h
 * @brief H002国密部分驱动
 * 
 * @date 2017-12-12   16:44:40
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_H002PINEXCMDDRIVER_H_
#define _LIBZHOUYB_H002PINEXCMDDRIVER_H_
//--------------------------------------------------------- 
#include "H002PinCmdDriver.h"
#include "../../pinpad/H002PinPadExDevAdapter.h"
using zhou_yb::application::pinpad::H002PinPadExDevAdapter;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/**
 * @brief H002国密部分驱动
 * @date 2017-12-12 16:48
 */
class H002PinExCmdDriver : 
    public CommonCmdDriver,
    public BaseDevAdapterBehavior<IInteractiveTrans>
{
protected:
    ComICCardCmdAdapter _cmdAdapter;
    H002PinPadExDevAdapter _pinAdapter;
public:
    H002PinExCmdDriver()
    {
        select_helper<LoggerSetter::SelecterType>::select(_logSetter),
            _cmdAdapter, _pinAdapter;
        _errGetter.Add(_pinAdapter).Select("CMD", _cmdAdapter);
        _pinAdapter.SelectDevice(_cmdAdapter);

        _RegisteAdapterCMD(H002PinExCmdDriver);
        _RegisteExceptCMD(H002PinExCmdDriver);

        _RegisteCMD(H002PinExCmdDriver, KeyNameToType);
        _RegisteCMD(H002PinExCmdDriver, AlgNameToType);
        _RegisteCMD(H002PinExCmdDriver, GenPublicKEY);
        _RegisteCMD(H002PinExCmdDriver, DownloadKEY);
        _RegisteCMD(H002PinExCmdDriver, PublicGenKEY);
        _RegisteCMD(H002PinExCmdDriver, PrivateGenKEY);
        _RegisteCMD(H002PinExCmdDriver, DownloadMK);
        _RegisteCMD(H002PinExCmdDriver, DownloadWK);
        _RegisteCMD(H002PinExCmdDriver, InputPWD);
        _RegisteCMD(H002PinExCmdDriver, ClearKEY);
        _RegisteCMD(H002PinExCmdDriver, WaitPinblock);
        _RegisteCMD(H002PinExCmdDriver, GetPinblock);
    }
    LC_CMD_ADAPTER_INVOKE(IInteractiveTrans, _cmdAdapter);
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(KeyNameToType);
        EXCEPT_CMD(AlgNameToType);
        return true;
    }
    LC_CMD_METHOD(KeyNameToType)
    {
        string sType = arg["KeyType"].To<string>();
        ByteArray typeArr(sType.c_str(), sType.length());
        if(StringConvert::Compare(typeArr, "RSA_Public", true))
        {
            
        }
        return true;
    }
    LC_CMD_METHOD(AlgNameToType)
    {
        return true;
    }
    /**
     * @brief 产生非对称算法密钥对并传出公钥
     * @param [in] KeyIndex : byte 非对称密钥密钥区号01-04
     * @param [in] KeyType  算法类型：
                                01H: 国际算法
                                02H: 国密算法
     * @param [int] KeyLength 密钥长度
                                算法类型为02H，此参数忽略
     * @return
     */
    LC_CMD_METHOD(GenPublicKEY)
    {
        byte kIndex = arg["KeyIndex"].To<byte>();
        byte kType = arg["KeyType"].To<byte>();
        byte kLength = arg["KeyLength"].To<byte>();
        ByteBuilder key(32);
        bool bOk = _pinAdapter.GenPublicKEY(kIndex, kType, key, kLength);
        if(bOk)
        {
            ByteBuilder buff(32);
            ByteConvert::ToAscii(key, buff);
            rlt.Put("KEY", buff.GetString());
            buff.Clear();
        }
        return bOk;
    }
    /**
     * @brief 下载非对称密钥
     * @date 2017-12-13 10:13
     *
     * @param [in] KeyIndex : byte 需要下载的密钥序号 [1,4]
     * @param [in] KeyType : byte 密钥类型
     * - 类型:
     *  - RSA_Public   1
     *  - RSA_Private  2
     *  - SM2_Public   3
     *  - SM2_Private  4
     * .
     * @param [in] KEY : hex 需要下载的密钥数据
     */
    LC_CMD_METHOD(DownloadKEY)
    {
        byte kIndex = arg["KeyIndex"].To<byte>();
        byte kType = arg["KeyType"].To<byte>();
        string sKey = arg["KEY"].To<string>();
        ByteBuilder key(32);
        DevCommand::FromAscii(sKey.c_str(), key);
        return _pinAdapter.DownloadKey(kIndex, kType, key);
    }
    /**
     * @brief 公钥产生会话密钥
     * @date 2017-12-13 10:48
     *
     * @param [in] Algorithm : byte 密钥算法用途
     * - 算法:
     *  - DES  1
     *  - 2DES 2
     *  - SM4  3
     *  - 3DES 4
     * .
     * @param [in] KeyType : string 密钥类别
     * - 类别:
     *  - SM2
     *  - RSA
     * .
     * @param [in] KeyIndex : byte 非对称密钥索引 [1,4]
     * @param [in] KeyLength : byte 需要生成的密钥长度
     *
     * @retval KEY : hex 生成的公钥数据
     * @retval KCV : hex 公钥KCV数据
     */
    LC_CMD_METHOD(PublicGenKEY)
    {
        byte alg = arg["Algorithm"].To<byte>();
        string sType = arg["KeyType"].To<string>();
        byte kIndex = arg["KeyIndex"].To<byte>();
        byte klen = arg["KeyLength"].To<byte>();
        bool isSm2 = StringConvert::StartWith(sType.c_str(), "SM2", true);
        ByteBuilder key(32);
        ByteBuilder kcv(16);
        bool bOK = _pinAdapter.PublicGenKey(alg, isSm2, kIndex, klen, key, kcv);
        if(bOK)
        {
            ByteBuilder buff(32);
            ByteConvert::ToAscii(key, buff);
            rlt.Put("KEY", buff.GetString());
            buff.Clear();
            ByteConvert::ToAscii(kcv, buff);
            rlt.Put("KCV", buff.GetString());
        }
        return bOK;
    }
    /**
     * @brief 私钥产生会话密钥
     * @date 2017-12-13 11:15
     *
     * @param [in] Algorithm : byte 密钥算法用途
     * - 算法:
     *  - DES  1
     *  - 2DES 2
     *  - SM4  3
     *  - 3DES 4
     * .
     * @param [in] KeyType : string 密钥类别
     * - 类别:
     *  - SM2
     *  - RSA
     * .
     * @param [in] KeyIndex : byte 非对称密钥索引 [1,4]
     * @param [in] KEY : hex 公钥加密的会话密钥密文
     *
     * @retval KCV : hex 会话密钥KCV
     */
    LC_CMD_METHOD(PrivateGenKEY)
    {
        byte alg = arg["Algorithm"].To<byte>();
        string sType = arg["KeyType"].To<string>();
        byte kIndex = arg["KeyIndex"].To<byte>();
        string sKey = arg["KEY"].To<string>();
        bool isSm2 = StringConvert::StartWith(sType.c_str(), "SM2", true);
        ByteBuilder key(32);
        DevCommand::FromAscii(sKey.c_str(), key);
        ByteBuilder kcv(16);
        bool bOK = _pinAdapter.PrivateGenKey(alg, isSm2, kIndex, key, kcv);
        if(bOK)
        {
            key.Clear();
            ByteConvert::ToAscii(kcv, key);
            rlt.Put("KCV", key.GetString());
        }
        return bOK;
    }
    /**
     * @brief 下载主密钥
     * @date 2017-12-13 11:20
     *
     * @param [in] MkIndex : byte 需要下载的对称主密钥索引 [0,0x0F]
     * @param [in] Algorithm : byte 密钥算法用途
     * - 算法:
     *  - DES  1
     *  - 2DES 2
     *  - SM4  3
     *  - 3DES 4
     * .
     * @param [in] KeyType : byte 密钥类型
     * - 类型:
     *  - RSA_Public  1
     *  - RSA_Private 2
     *  - SM2_Public  3
     *  - SM2_Private 4
     *  - SessionKey  5
     * .
     * @param [in] KeyIndex : byte 非对称密钥索引号 [1,4]
     * @param [in] KEY : hex 需要下载的主密钥密文
     * @param [in] KCV : hex 需要下载的主密钥校验值
     *
     * @retval KeyLength : size_t 密钥长度
     * @retval KCV : hex 密钥KCV
     * 
     * @retval KEY : hex 主密钥密文
     */
    LC_CMD_METHOD(DownloadMK)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte alg = arg["Algorithm"].To<byte>();
        byte kType = arg["KeyType"].To<byte>();
        byte kIndex = arg["KeyIndex"].To<byte>();
        string sKey = arg["KEY"].To<string>();
        string sKcv = arg["KCV"].To<string>();
        ByteBuilder key(32);
        ByteBuilder kcv(16);
        DevCommand::FromAscii(sKey.c_str(), key);
        DevCommand::FromAscii(sKcv.c_str(), kcv);
        ByteBuilder data(64);
        bool bOK = _pinAdapter.DownloadMK(mkIndex, alg, kType, kIndex, key, kcv, data);
        if(bOK)
        {
            ASSERT_FuncErr(data.GetLength() >= 17, DeviceError::RecvFormatErr);
            ByteBuilder buff(32);
            ByteArray fmt = data;
            // RSA公钥 和 SM2公钥
            if(kType == 0x01 || kType == 0x03)
            {
                size_t len = data[0];
                ASSERT_FuncErr(data.GetLength() >= (18 + len), DeviceError::RecvFormatErr);
                ByteConvert::ToAscii(data.SubArray(1, len), buff);
                rlt.Put("KEY", buff.GetString());
                len += 1;
                buff.Clear();
                fmt.SubArray(len);
            }
            size_t kcvlen = fmt[0];
            rlt.Put("KeyLength", ArgConvert::ToString(kcvlen));
            ByteConvert::ToAscii(fmt.SubArray(1), buff);
            rlt.Put("KCV", buff.GetString());
        }
        return bOK;
    }
    /**
     * @brief 下载工作密钥
     * @date 2017-12-13 15:17
     *
     * @param [in] MkIndex : byte 需要下载的对称主密钥索引 [0,0x0F]
     * @param [in] WkIndex : byte 需要下载的对称工作密钥索引 [0,0x0F]
     * @param [in] Algorithm : byte 密钥算法用途
     * - 算法:
     *  - DES  1
     *  - 2DES 2
     *  - SM4  3
     *  - 3DES 4
     * .
     * @param [in] KeyType : byte 密钥类型
     * - 类型:
     *  - RSA_Public  1
     *  - RSA_Private 2
     *  - SM2_Public  3
     *  - SM2_Private 4
     *  - SessionKey  5
     *  - MasterKey   6
     * .
     * @param [in] KeyIndex : byte 非对称密钥索引号 [1,4]
     * @param [in] KEY : hex 需要下载的主密钥密文
     * @param [in] KCV : hex 需要下载的主密钥校验值
     *
     * @retval KeyLength : size_t 密钥长度
     * @retval KCV : hex 密钥KCV
     *
     * @retval KEY : hex 工作密钥密文
     */
    LC_CMD_METHOD(DownloadWK)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        byte alg = arg["Algorithm"].To<byte>();
        byte kType = arg["KeyType"].To<byte>();
        byte kIndex = arg["KeyIndex"].To<byte>();
        string sKey = arg["KEY"].To<string>();
        string sKcv = arg["KCV"].To<string>();
        ByteBuilder key(32);
        ByteBuilder kcv(16);
        DevCommand::FromAscii(sKey.c_str(), key);
        DevCommand::FromAscii(sKcv.c_str(), kcv);
        ByteBuilder data(64);
        bool bOK = _pinAdapter.DownloadWK(mkIndex, wkIndex, alg, kType, kIndex, key, kcv, data);
        if(bOK)
        {
            ASSERT_FuncErr(data.GetLength() >= 17, DeviceError::RecvFormatErr);
            ByteBuilder buff(32);
            ByteArray fmt = data;
            // RSA公钥 和 SM2公钥
            if(kType == 0x01 || kType == 0x03)
            {
                size_t len = data[0];
                ASSERT_FuncErr(data.GetLength() >= (18 + len), DeviceError::RecvFormatErr);
                ByteConvert::ToAscii(data.SubArray(1, len), buff);
                rlt.Put("KEY", buff.GetString());
                len += 1;
                buff.Clear();
                fmt.SubArray(len);
            }
            size_t kcvlen = fmt[0];
            rlt.Put("KeyLength", ArgConvert::ToString(kcvlen));
            ByteConvert::ToAscii(fmt.SubArray(1), buff);
            rlt.Put("KCV", buff.GetString());
        }
        return bOK;
    }
    /**
     * @brief 输入密码(不带*号)
     * @date 2017-12-13 15:50
     *
     * @param [in] MkIndex : byte 主密钥序号
     * @param [in] WkIndex : byte 工作密钥号
     * @param [in] Min : byte [default:4] 期望输入的最小长度
     * @param [in] Max : byte [default:6] 期望输入的最大长度
     * @param [in] IsEnter : bool [default:false] 是否需要按回车键结束
     * @param [in] IsReVoice : bool [default:false] 是否语音提示再次输入
     * @param [in] IsPinblock : bool [default:true] 是否启用PINBLOCK模式
     * @param [in] PinblockByte : byte [default:0xFF] 启用PINBLOCK时的后补字节
     * @param [in] Accno : string [default:""] 帐号(为空时不启用PINBLOCK模式)
     *
     * @retval Pwd : hex 输入的密码密文
     */
    LC_CMD_METHOD(InputPWD)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        byte minlen = arg["Min"].To<byte>();
        byte maxlen = arg["Max"].To<byte>();
        bool isEnter = arg["IsEnter"].To<bool>(false);
        bool isReVoice = arg["IsReVoice"].To<bool>(false);
        string sAccno = arg["Accno"].To<string>();
        bool isAccnoEmpty = (sAccno.length() < 1);
        bool isPinblock = arg["IsPinblock"].To<bool>(!isAccnoEmpty);
        byte pinblockByte = arg["PinblockByte"].To<byte>(0xFF);
        ByteBuilder pwd(8);
        bool bOK = _pinAdapter.InputPwd(mkIndex, wkIndex, minlen, maxlen, isEnter, isReVoice, isPinblock, pinblockByte, sAccno.c_str(), pwd);
        if(bOK)
        {
            ByteBuilder buff(8);
            ByteConvert::ToAscii(pwd, buff);
            rlt.Put("Pwd", buff.GetString());
        }
        return bOK;
    }
    /**
     * @brief 清空密钥
     * @date 2017-12-13 16:12
     *
     * @param [in] KeyType : byte 密钥类型
     * - 类型:
     *  - 1 : 非对称密钥
     *  - 2 : 会话密钥
     *  - 3 : 主密钥
     *  - 4 : 工作密钥
     * .
     * @param [in] KeyIndex : byte 主密钥序号(非对称密钥时为密钥类型)
     * - 非对称密钥类型
     *  - 1 : RSA_Public
     *  - 2 : RSA_Private
     *  - 3 : SM2_Public
     *  - 4 : SM2_Private
     *  - 5 : SessionKey
     *  - 6 : MasterKey
     * .
     * @param [in] WkIndex : byte 工作密钥序号
     */
    LC_CMD_METHOD(ClearKEY)
    {
        byte kType = arg["KeyType"].To<byte>();
        byte kIndex = arg["KeyIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        return _pinAdapter.ClearKey(kType, kIndex, wkIndex);
    }
    /**
     * @brief 开始带*号返回输入密码
     * @date 2017-12-13 15:50
     *
     * @param [in] Min : byte [default:4] 期望输入的最小长度
     * @param [in] Max : byte [default:6] 期望输入的最大长度
     * @param [in] IsEnter : bool [default:false] 是否需要按回车键结束
     * @param [in] IsReVoice : bool [default:false] 是否语音提示再次输入
     */
    LC_CMD_METHOD(WaitPinblock)
    {
        byte minlen = arg["Min"].To<byte>(4);
        byte maxlen = arg["Max"].To<byte>(6);
        bool isEnter = arg["IsEnter"].To<bool>(false);
        bool isReVoice = arg["IsReVoice"].To<bool>(false);
        return _pinAdapter.WaitPinblock(minlen, maxlen, isEnter, isReVoice);
    }
    /**
     * @brief 获取密码数据(带*号)
     * @date 2017-12-13 15:50
     *
     * @param [in] MkIndex : byte 对称密钥区号30-3F
     * @param [in] WkIndex : byte 工作密钥索引30-3F
     * @param [in] IsPinblock : bool [default:true] 是否启用PINBLOCK模式
     * @param [in] PinblockByte : byte [default:0xFF] 启用PINBLOCK时的后补字节
     * @param [in] Accno : string [default:""] 帐号(为空时不启用PINBLOCK模式)
     *
     * @retval Pwd : hex 输入的密码密文
     */
    LC_CMD_METHOD(GetPinblock)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        string sAccno = arg["Accno"].To<string>();
        bool isAccnoEmpty = (sAccno.length() < 1);
        bool isPinblock = arg["IsPinblock"].To<bool>(!isAccnoEmpty);
        byte pinblockByte = arg["PinblockByte"].To<byte>(0xFF);
        ByteBuilder pwd(8);
        bool bOK = _pinAdapter.GetPinblock(mkIndex, wkIndex, isPinblock, pinblockByte, sAccno.c_str(), pwd);
        if(bOK)
        {
            ByteBuilder buff(8);
            ByteConvert::ToAscii(pwd, buff);
            rlt.Put("Pwd", buff.GetString());
        }
        return bOK;
    }
};
//--------------------------------------------------------- 
} // namespace pinpad
} // namespace application 
} // namespace zhou_yb 
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_H002PINEXCMDDRIVER_H_
//========================================================= 